package string;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

public class Anagram {

	// in-memory dictionary object
	private static Map<String, TreeSet<String>> dictionaryMap = new HashMap<String, TreeSet<String>>();


	// load the dictionary in memory
	static{
		if(dictionaryMap == null || dictionaryMap.isEmpty())
			dictionaryMap = ((new Anagram()).new Process()).getDictionaryMap();
	}


	// API starts ---------------------------------------------------

	
	// returns whether given word is a valid english word
	public static boolean isValidWord(String word){
		char[] charArray = word.toCharArray();
		Arrays.sort(charArray);
		//String sortedWord = charArray.toString(); // don't try this
		String sortedWord = new String(charArray);

		Set<String> anagramSet = dictionaryMap.get(sortedWord);
		if(anagramSet != null && anagramSet.contains(word)){
			return true;
		}
		return false;
	}


	// returns in-memory dictionary object
	public static Map<String, TreeSet<String>> getAnagramMap(){
		return dictionaryMap;
	}


	// returns all anagrams of the given word
	public static Set<String> getAnagrams(String word){
		char[] charArray = word.toCharArray();
		Arrays.sort(charArray);
		String str = new String(charArray);

		Set<String> anagramList = dictionaryMap.get(str);
		return anagramList;
	}


	// return all set of anagrams in the dictionary
	public static void getAnagrams(){
		((new Anagram()).new Process()).writeToFile();
	}

	

	// API ends ---------------------------------------------------


	// This inner class: 
	// 1. loads dictionary.txt into memory
	// 2. writes all the anagrams to a file
	private class Process{ // inner class starts

		private Map<String, TreeSet<String>> dictMap = new HashMap<String, TreeSet<String>>(); 

		Map<String, TreeSet<String>> getDictionaryMap(){
			if(dictMap.isEmpty()){
				collectWords();
			}

			return dictMap;
		}


		// reads word from dictionary.txt one-by-one
		private void collectWords(){
			BufferedReader br = null;

			try {

				InputStream is = Anagram.class.getResourceAsStream("app.conf");
				Properties properties = new Properties();
				properties.load(is);

				// location of dictionary in file system
				String dictionaryLocation = properties.getProperty("dictionaryLocation");

				br = new BufferedReader(new FileReader(dictionaryLocation));
				StringBuilder sb = new StringBuilder();
				String line = br.readLine();

				while (line != null) {
					if(line != null && line.trim().length() > 0)
						preProcess(line);
					line = br.readLine();
				}
			}catch (FileNotFoundException ex){
				ex.printStackTrace();
			}catch (IOException ex){
				ex.printStackTrace();
			}finally {
				try{
					if(br != null){
						br.close();
					}
				}catch(IOException ex){
					ex.printStackTrace();
				}
			}
		}


		// loads given word into memory along with its anagrams
		private void preProcess(String word){
			char[] charArray = word.toCharArray();
			Arrays.sort(charArray);
			String str = new String(charArray);

			TreeSet<String> wordList = dictMap.get(str);
			if(wordList != null){
				wordList.add(word);
				dictMap.put(str, wordList);
			}else{
				wordList = new TreeSet<String>();
				wordList.add(word);
				dictMap.put(str, wordList);
			}
		}	


		// writes all possible anagrams to the specified file
		void writeToFile(){
			BufferedWriter br = null;

			try {
				InputStream is = Anagram.class.getResourceAsStream("app.conf");

				Properties properties = new Properties();
				properties.load(is);

				// location where all the anagrams in given dictionary will be written
				String anagramsListLocation = properties.getProperty("anagramsListLocation");

				br = new BufferedWriter(new FileWriter(anagramsListLocation));

				Set<String> keySet = dictionaryMap.keySet();
				for(String key: keySet){
					Set<String> values = dictionaryMap.get(key);
					if(values.size() > 1){
						StringBuilder sb = new StringBuilder();
						sb.append(values);
						br.append(sb.toString()+"\n");
					}
				}
			}catch (FileNotFoundException ex){
				ex.printStackTrace();
			}catch (IOException ex){
				ex.printStackTrace();
			}finally {
				try{
					if(br != null){
						br.close();
					}
				}catch(IOException ex){
					ex.printStackTrace();
				}
			}		
		}
	} // inner class ends
}